package cn.cool.middleware.biz_exception_retry.domain.service;

import cn.cool.middleware.biz_exception_retry.domain.IBizExceptionRetryModuleService;
import cn.cool.middleware.biz_exception_retry.domain.adapter.repository.IBizExceptionRetryRepository;
import cn.cool.middleware.biz_exception_retry.domain.model.valobj.BizExceptionRetryModuleVO;
import cn.cool.middleware.biz_exception_retry.types.common.helper.BizMemoryRetryHelper;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;

import javax.annotation.Resource;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalUnit;
import java.util.Date;

@Slf4j
public class BizExceptionRetryModuleService implements IBizExceptionRetryModuleService {
    @Resource
    private IBizExceptionRetryRepository repository;

    @Override
    public boolean tryLock(String exceptionModule, Integer interValMillis) {
        try {
            if (StrUtil.isBlank(exceptionModule) || interValMillis == null || interValMillis == 0) {
                log.error("[@BizExceptionRetry] BizExceptionRetryModuleService exceptionModule is null or interValMillis is null");
                return false;
            }

            BizExceptionRetryModuleVO bizExceptionRetryModuleVO = repository.selectByExceptionModule(exceptionModule);
            if (ObjUtil.isNull(bizExceptionRetryModuleVO)) {
                // 执行 insert（唯一索引控制）
                try {
                    repository.insertModule(exceptionModule);
                    bizExceptionRetryModuleVO = repository.selectByExceptionModule(exceptionModule);
                } catch (Throwable throwable) {
                    log.error("[@BizExceptionRetry] insert {} to db failed, {} is already exists", exceptionModule, exceptionModule);
                    return false;
                }
            }

            Date now = new Date();
            Date oldLockTime = bizExceptionRetryModuleVO.getLockTime();
            Instant instant = oldLockTime.toInstant().plus(interValMillis, ChronoUnit.MILLIS);
            Date lockEndTime = Date.from(instant);
            if (bizExceptionRetryModuleVO.getLockStatus() == 0 || lockEndTime.before(now)) {
                // 尝试加锁
                int lockModule = repository.lockModule(exceptionModule, oldLockTime);
                return lockModule == 1;
            }

        } catch (Throwable throwable) {
            log.error("[@BizExceptionRetry] BizExceptionRetryModuleService tryLock exception; exceptionModule:{}", exceptionModule, throwable);
        }

        return false;
    }

    @Override
    public void unLock(String exceptionModule) {
        try {
            repository.unLock(exceptionModule);
        } catch (Throwable throwable) {
            log.error("[@BizExceptionRetry] 业务异常定时重试 - 释放分布式锁失败", throwable);
        }
    }
}
